﻿#region

using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

#endregion

namespace EditeurSyntaxiqueVocal.Forms
{
    public partial class FormeDeplace : Form
    {
        private int captionHeight;
        private Point closeButtonOffset;
        private Size closeButtonSize;
        private Dictionary<string, Rectangle> elementRectangles = new Dictionary<string, Rectangle>();
        private int frameThickness;
        private Size gripperSize;
        private bool isClosing;
        private bool isMin;
        private bool isMoving;
        private bool isResizing;
        private Point minButtonOffset;
        private Size minButtonSize;
        private Point originalClick;
        private VisualStyleRenderer renderer;
        private Point resizeOffset;
        private int statusHeight = 22;
        private Dictionary<string, VisualStyleElement> windowElements = new Dictionary<string, VisualStyleElement>();

        public FormeDeplace()
        {
            InitializeComponent();
            //
            BackColor = Color.Azure;
            //this.DoubleBuffered = true;
            MinimumSize = new Size(200, 300);
            Font = SystemFonts.CaptionFont;
            Text = "Simulated Window";

            // Insert the VisualStyleElement objects into the Dictionary.
            windowElements.Add("windowCaption", VisualStyleElement.Window.Caption.Active);
            windowElements.Add("windowBottom", VisualStyleElement.Window.FrameBottom.Active);
            windowElements.Add("windowLeft", VisualStyleElement.Window.FrameLeft.Active);
            windowElements.Add("windowRight", VisualStyleElement.Window.FrameRight.Active);
            windowElements.Add("windowClose", VisualStyleElement.Window.CloseButton.Normal);
            windowElements.Add("windowMin", VisualStyleElement.Window.MinButton.Normal);
            //windowElements.Add("windowMax", VisualStyleElement.Window.MaxButton.Normal);
            windowElements.Add("statusBar", VisualStyleElement.Status.Bar.Normal);
            windowElements.Add("statusGripper", VisualStyleElement.Status.Gripper.Normal);

            // Get the sizes and location offsets for the window parts  
            // as specified by the visual style, and then use this 
            // information to calcualate the rectangles for each part.
            GetPartDetails();
            CalculateRectangles();

            MouseDown += ImitationWindow_MouseDown;
            MouseUp += ImitationWindow_MouseUp;
            MouseMove += ImitationWindow_MouseMove;
        }

        // Get the sizes and offsets for the window parts as specified  
        // by the visual style.
        private void GetPartDetails()
        {
            // Do nothing further if visual styles are not enabled.
            if (!Application.RenderWithVisualStyles)
            {
                return;
            }

            using (Graphics g = CreateGraphics())
            {
                // Get the height of the window caption.
                if (SetRenderer(windowElements["windowCaption"]))
                {
                    captionHeight = renderer.GetPartSize(g,
                                                         ThemeSizeType.True).Height;
                }

                // Get the size and offset of the close button.
                if (SetRenderer(windowElements["windowClose"]))
                {
                    closeButtonSize =
                        renderer.GetPartSize(g, ThemeSizeType.True);
                    closeButtonOffset =
                        renderer.GetPoint(PointProperty.Offset);
                }

                // Get the size and offset of the close button.
                if (SetRenderer(windowElements["windowMin"]))
                {
                    minButtonSize =
                        renderer.GetPartSize(g, ThemeSizeType.True);
                    minButtonOffset =
                        renderer.GetPoint(PointProperty.Offset);
                }


                // Get the thickness of the left, bottom, 
                // and right window frame.
                if (SetRenderer(windowElements["windowLeft"]))
                {
                    frameThickness = renderer.GetPartSize(g,
                                                          ThemeSizeType.True).Width;
                }

                // Get the size of the resizing gripper.
                if (SetRenderer(windowElements["statusGripper"]))
                {
                    gripperSize = renderer.GetPartSize(g,
                                                       ThemeSizeType.True);
                }
            }
        }

        // Use the part metrics to determine the current size 
        // of the rectangles for all of the window parts.
        private void CalculateRectangles()
        {
            int heightMinusFrame =
                ClientRectangle.Height - frameThickness;

            // Calculate the window frame rectangles and add them
            // to the Dictionary of rectangles.
            elementRectangles["windowCaption"] =
                new Rectangle(0, 0,
                              ClientRectangle.Width, captionHeight);
            elementRectangles["windowBottom"] =
                new Rectangle(0, heightMinusFrame,
                              ClientRectangle.Width, frameThickness);
            elementRectangles["windowLeft"] =
                new Rectangle(0, captionHeight, frameThickness,
                              heightMinusFrame - captionHeight);
            elementRectangles["windowRight"] =
                new Rectangle(ClientRectangle.Width - frameThickness,
                              captionHeight, frameThickness,
                              heightMinusFrame - captionHeight);

            // Calculate the window button rectangle and add it
            // to the Dictionary of rectangles.
            elementRectangles["windowClose"] =
                new Rectangle(
                    ClientRectangle.Right - closeButtonSize.Width - elementRectangles["windowRight"].Width - 4, 2,
                    closeButtonSize.Width + 4, closeButtonSize.Height + 2);

            elementRectangles["windowMin"] =
                new Rectangle(
                    ClientRectangle.Right - minButtonSize.Width - elementRectangles["windowClose"].Width - 28, 2,
                    minButtonSize.Width + 20, minButtonSize.Height + 2);

            // Calculate the status bar rectangles and add them
            // to the Dictionary of rectangles.
            elementRectangles["statusBar"] =
                new Rectangle(frameThickness,
                              heightMinusFrame - statusHeight,
                              ClientRectangle.Width - (2*frameThickness),
                              statusHeight);
            elementRectangles["statusGripper"] =
                new Rectangle(ClientRectangle.Right -
                              gripperSize.Width - frameThickness,
                              heightMinusFrame - gripperSize.Height,
                              gripperSize.Width, gripperSize.Height);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            // Ensure that visual styles are supported.
            if (!Application.RenderWithVisualStyles)
            {
                //this.Text = "Visual styles are not enabled.";
                //TextRenderer.DrawText(e.Graphics, this.Text,
                //    this.Font, this.Location, this.ForeColor);
                return;
            }

            // Set the clip region to define the curved corners 
            // of the caption.
            SetClipRegion();

            // Draw each part of the window.
            foreach (KeyValuePair<string, VisualStyleElement> entry
                in windowElements)
            {
                if (SetRenderer(entry.Value))
                {
                    renderer.DrawBackground(e.Graphics, elementRectangles[entry.Key]);
                }
            }

            // Draw the caption text.
            TextRenderer.DrawText(e.Graphics, Text, Font,
                                  elementRectangles["windowCaption"], Color.White,
                                  TextFormatFlags.VerticalCenter |
                                  TextFormatFlags.HorizontalCenter);
        }

        // Initiate dragging, resizing, or closing the imitation window.
        private void ImitationWindow_MouseDown(object sender, MouseEventArgs e)
        {
            // The user clicked the close button.
            if (elementRectangles["windowClose"].Contains(e.Location))
            {
                windowElements["windowClose"] =
                    VisualStyleElement.Window.CloseButton.Pressed;
                isClosing = true;
            }

                // The user clicked the close button.
            else if (elementRectangles["windowMin"].Contains(e.Location))
            {
                windowElements["windowMin"] =
                    VisualStyleElement.Window.MinButton.Pressed;
                isMin = true;
            }

                // The user clicked the status grip.
            else if (elementRectangles["statusGripper"].Contains(e.Location))
            {
                isResizing = true;
                Cursor = Cursors.SizeNWSE;
                resizeOffset.X = Right - Left - e.X;
                resizeOffset.Y = Bottom - Top - e.Y;
            }

                // The user clicked the window caption.
            else if (elementRectangles["windowCaption"].
                Contains(e.Location))
            {
                isMoving = true;
                originalClick.X = e.X;
                originalClick.Y = e.Y;
            }

            Invalidate();
        }

        // Stop any current resizing or moving actions.
        private void ImitationWindow_MouseUp(object sender, MouseEventArgs e)
        {
            // Stop moving the location of the window rectangles.
            if (isMoving)
            {
                isMoving = false;
            }

                // Change the cursor back to the default if the user 
                // stops resizing.
            else if (isResizing)
            {
                isResizing = false;
            }

                // Close the application if the user clicks the 
                // close button.
            else if (elementRectangles["windowClose"].
                         Contains(e.Location) && isClosing)
            {
                Close();
            }
            else if (elementRectangles["windowMin"].
                         Contains(e.Location) && isMin)
            {
                WindowState = FormWindowState.Minimized;
                windowElements["windowMin"] =
                    VisualStyleElement.Window.MinButton.Normal;
            }
        }

        // Handle resizing or moving actions.
        private void ImitationWindow_MouseMove(object sender, MouseEventArgs e)
        {
            // The left mouse button is down.
            if ((MouseButtons.Left & e.Button) == MouseButtons.Left)
            {
                // Calculate the new control size if the user is 
                // dragging the resizing grip.
                if (isResizing)
                {
                    Width = e.X + resizeOffset.X;
                    Height = e.Y + resizeOffset.Y;
                    CalculateRectangles();
                }

                    // Calculate the new location of the control if the  
                    // user is dragging the window caption.
                else if (isMoving)
                {
                    int XChange = Location.X +
                                  (e.X - originalClick.X);
                    int YChange = Location.Y +
                                  (e.Y - originalClick.Y);
                    Location = new Point(XChange, YChange);
                }

                    // Cancel the closing action if the user clicked  
                    // and held down on the close button, and has dragged   
                    // the pointer outside the button.
                else if (!elementRectangles["windowClose"].
                              Contains(e.Location) && isClosing)
                {
                    isClosing = false;
                    windowElements["windowClose"] =
                        VisualStyleElement.Window.CloseButton.Normal;
                }
                else if (!elementRectangles["windowMin"].
                              Contains(e.Location) && isMin)
                {
                    isMin = false;
                    windowElements["windowMin"] =
                        VisualStyleElement.Window.MinButton.Normal;
                }
            }
            else // The left mouse button is not down.
            {
                // Paint the close button hot if the cursor is on it.
                Rectangle closeRectangle =
                    elementRectangles["windowClose"];
                windowElements["windowClose"] =
                    closeRectangle.Contains(e.Location)
                        ?
                            VisualStyleElement.Window.CloseButton.Hot
                        :
                            VisualStyleElement.Window.CloseButton.Normal;

                Rectangle MinRectangle =
                    elementRectangles["windowMin"];
                windowElements["windowMin"] =
                    MinRectangle.Contains(e.Location)
                        ?
                            VisualStyleElement.Window.MinButton.Hot
                        :
                            VisualStyleElement.Window.MinButton.Normal;

                // Use a resizing cursor if the cursor is on the 
                // status grip.
                Rectangle gripRectangle =
                    elementRectangles["statusGripper"];
                Cursor = gripRectangle.Contains(e.Location)
                             ?
                                 Cursors.SizeNWSE
                             : Cursors.Default;
            }

            Refresh();
        }

        // Calculate and set the clipping region for the control  
        // so that the corners of the title bar are rounded.
        private void SetClipRegion()
        {
            if (!Application.RenderWithVisualStyles)
            {
                return;
            }

            using (Graphics g = CreateGraphics())
            {
                // Get the current region for the window caption.
                if (SetRenderer(windowElements["windowCaption"]))
                {
                    Region clipRegion = renderer.GetBackgroundRegion(
                        g, elementRectangles["windowCaption"]);

                    // Get the client rectangle, but exclude the region 
                    // of the window caption.
                    int height = (int) clipRegion.GetBounds(g).Height;
                    Rectangle nonCaptionRect = new Rectangle(
                        ClientRectangle.X,
                        ClientRectangle.Y + height,
                        ClientRectangle.Width,
                        ClientRectangle.Height - height);

                    // Add the rectangle to the caption region, and  
                    // make this region the form's clipping region.
                    clipRegion.Union(nonCaptionRect);
                    Region = clipRegion;
                }
            }
        }

        // Set the VisualStyleRenderer to a new element.
        private bool SetRenderer(VisualStyleElement element)
        {
            if (!VisualStyleRenderer.IsElementDefined(element))
            {
                return false;
            }

            if (renderer == null)
            {
                renderer = new VisualStyleRenderer(element);
            }
            else
            {
                renderer.SetParameters(element);
            }

            return true;
        }
    }
}